package com.miyake.dsp.analyzer;

import com.miyake.dsp.ComplexArray;
import com.miyake.dsp.Processor;
import com.miyake.dsp.common.UnitConverter;

public class Threshold implements Processor {

	private ThresholdSetting setting;
	private ComplexArray source;
	private Double center;
	private Double width;

	public Threshold(ThresholdSetting setting) {
		this.setting = setting;
	}
	
	@Override
	public void setSource(ComplexArray source) {
		this.source = source;
	}

	@Override
	public ComplexArray getSource() {
		return this.source;
	}

	private void calculate() {
		int maxIndex = setting.getPeakIndex();
		double[] d = source.getRealPart();
		double max = d[setting.getPeakIndex()];
		double level = max / UnitConverter.toLinear(setting.getThreshold());
		
		int leftIndex = 0, rightIndex = 0;
		for (int i = maxIndex; i > 0; i--) {
			if (d[i] < level) {
				leftIndex = i;
				break;
			}
		}
		for (int i = maxIndex; i < d.length; i++) {
			if (d[i] < level) {
				rightIndex = i;
				break;
			}
		}
		
		double x1 = getInterpolate(level, leftIndex, leftIndex+1);
		double x2 = getInterpolate(level, rightIndex-1, rightIndex);
		
		center = (x1+x2)/2.0;
		width = (x2-x1);
	}
	
	@Override
	public ComplexArray getProcessed() {
		calculate();
		double[] d = new double[2];
		d[0] = center;
		d[1] = width;
		return new ComplexArray(d);
	}

	private double getInterpolate(double level, int index1, int index2) {
		double[] d = source.getRealPart();
		double step = (setting.getEndValue() - setting.getStartValue()) / (d.length-1);
		double x1 = setting.getStartValue() + step * index1;
		double x2 = setting.getStartValue() + step * index2;
		double y1 = d[index1];
		double y2 = d[index2];
		//(y-y1)(x2-x1)/(y2-y1)+x1=x
		return (level - y1)*(x2-x1)/(y2-y1) + x1;
	}

	@Override
	public Object getSetting() {
		return this.setting;
	}

	public double getCenter() {
		if (center == null) {
			calculate();
		}
		return center;
	}

	public double getWidth() {
		if (width == null) {
			calculate();
		}
		return width;
	}

}
